package com.mass.core.framework.security;

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.util.ObjectUtils;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private CustomUserDetailsService myUserDetailsService;
	
	@Resource
    private SessionRegistry sessionRegistry;
	
	@Value("${wx.context-path:false}")
   	private String wxPath;    //排除拦截
	
	@Value("${only.login:false}")
   	private String onlyLogin;    //是否唯一登录
	
	@Bean
    public SessionRegistry getSessionRegistry(){
        SessionRegistry sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    }
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth)
			throws Exception {
		auth.userDetailsService(myUserDetailsService).passwordEncoder(
				passwordEncoder());
	}

	@Bean
	public Md5PasswordEncoder passwordEncoder() {
		return new Md5PasswordEncoder();
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/public/**", "/js/**");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		String matchers[] =null;
		String matchersList[] = new String[]{"/*.html", "/favicon.ico",
				"/**/*.html", "/**/*.css", "/**/*.js","/fileURL/**","/service/**"
				,"/config"
				,"/error"
				,"/webSocket/**"
				,"/any-socket/**"
				,"/sign/logout"};
		if(!ObjectUtils.isEmpty(wxPath) && !"false".equals(wxPath)){
        	if(wxPath.indexOf(",")>=0){
        		String [] list = wxPath.split(",");
        		matchers = new String[list.length+matchersList.length];
        		for(int i=0;i<matchers.length;i++){
        			if(i<matchersList.length){
        				matchers[i]=matchersList[i];
        			}else{
        				matchers[i]=list[i-matchersList.length];
        			}
        		}
        	}else{
        		matchers = new String[matchersList.length+1];
        		for(int i=0;i<matchersList.length;i++){
        			matchers[i]=matchersList[i];
        		}
        		matchers[matchersList.length] = wxPath;
        	}
        }else{
        	matchers = matchersList;
        }
		
		http.headers().frameOptions().disable();
		http.addFilterBefore(corsFilter(), ChannelProcessingFilter.class);
		http.csrf()
				.disable()
				.authorizeRequests()
				.antMatchers("/", "/sign/getCurrentUserInfo","/sign/login")
				.permitAll()
				.antMatchers(matchers)
				.permitAll()
				.anyRequest()
				.authenticated()
				.and()
				.formLogin()
				.usernameParameter("username")
				.passwordParameter("password")
				.loginProcessingUrl("/sign/in")
				.successHandler(new RestAuthenticationSuccessHandler())
				// 登陆失败后的处理
				.failureHandler(new RestAuthenticationFailureHandler())
				.and()
				// 登出后的处理
				.logout().logoutSuccessHandler(new RestLogoutSuccessHandler())
				.and().exceptionHandling()
				.authenticationEntryPoint(new RestAuthenticationEntryPoint())
				.and().httpBasic()
				.authenticationEntryPoint(new RestAuthenticationEntryPoint());
		if(!ObjectUtils.isEmpty(onlyLogin) && "true".equals(onlyLogin)){
			//以下这句就可以控制单个用户只能创建一个session，也就只能在服务器登录一次        
			http.sessionManagement()//Session管理器
			.maximumSessions(1)
			.sessionRegistry(sessionRegistry)
			.expiredUrl("/Member/Login.html");
		}

	}

	/**
	 * 登陆成功后的处理
	 */
	public static class RestAuthenticationSuccessHandler extends
			SimpleUrlAuthenticationSuccessHandler {

		@Override
		public void onAuthenticationSuccess(HttpServletRequest request,
				HttpServletResponse response, Authentication authentication)
				throws ServletException, IOException {

			clearAuthenticationAttributes(request);
			request.getRequestDispatcher("/sign/login").forward(request,
					response);
		}
	}

	/**
	 * 登陆失败后的处理
	 */
	public static class RestAuthenticationFailureHandler extends
			SimpleUrlAuthenticationFailureHandler {

		@Override
		public void onAuthenticationFailure(HttpServletRequest request,
				HttpServletResponse response, AuthenticationException exception)
				throws IOException, ServletException {

			/*Map<String, Object> error = new HashMap<String, Object>();  
            error.put("message", "用户名或密码错误！");
            error.put("code", "1001");
            error.put("data", null); // 兼容extjs form loading    
            
            response.setContentType("json");  
            response.setCharacterEncoding("UTF-8");
            String json = JSONObject.valueToString(error);
            response.getWriter().write(json);  
            response.getWriter().flush(); */
			request.getRequestDispatcher("/sign/login").forward(request,
					response);
		}
	}

	/**
	 * 登出成功后的处理
	 */
	public static class RestLogoutSuccessHandler extends
			SimpleUrlLogoutSuccessHandler {

		@Override
		public void onLogoutSuccess(HttpServletRequest request,
				HttpServletResponse response, Authentication authentication)
				throws IOException, ServletException {
			// Do nothing!
		}
	}

	/**
	 * 权限不通过的处理
	 */
	public static class RestAuthenticationEntryPoint implements
			AuthenticationEntryPoint {

		
		public void commence(HttpServletRequest request,
				HttpServletResponse response,
				AuthenticationException authException) throws IOException {
			response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
					"Authentication Failed: " + authException.getMessage());
		}
	}

	@Bean
	public Filter corsFilter() {
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		CorsConfiguration config = new CorsConfiguration();
		config.setAllowCredentials(true);
		config.addAllowedOrigin("*");
		config.addAllowedHeader("*");
		config.addAllowedMethod("*");
		config.addExposedHeader("jwtToken");
		source.registerCorsConfiguration("/**", config);
		return new CorsFilter(source);
	}

}